package com.bugbuff.dubbo.server.service;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bugbuff.common.pojo.Admin;
import com.bugbuff.common.utils.AdminThreadLocal;
import com.bugbuff.common.vo.ErrorResult;
import com.bugbuff.dubbo.server.mapper.AdminMapper;
import com.bugbuff.dubbo.server.vo.AdminVo;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestHeader;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class AdminService {


    /*
    * 导入RedisTemplate模板
    * */
    @Autowired
    private RedisTemplate<String,String> redisTemplate;


    //定义redisCode的key键
    //private static final String ADMIN_REDIS_KEY = "ADMIN_USER_";


    @Value("${jwt.secret}")
    private String secret;


    @Autowired
    private AdminMapper adminMapper;


    /**
     * 登录
     * @param username 账号
     * @param password 密码
     * @param code 验证码
     * @param uuid 同获取验证码的uuid
     * @return
     */
    public Map<String,String> login(String username, String password, String code, String uuid) {
        Map<String,String> result = new HashMap<>();
        //判断传参是否为空
        if (!ObjectUtil.isAllNotEmpty(username,password,code,uuid)){
            //传参有为空，直接返回前端错误
            //return ErrorResult.builder().errCode("000001").errMessage("请正确输入登录信息！！").build();
            log.error("请正确输入登录信息！！");
            result.put("message","请正确输入登录信息！！");
            return result;
        }
        //设置RedisCode的key，使用uuid
        String redisKey =uuid;

        //判断验证码是否失效
        Boolean flag = redisTemplate.hasKey(redisKey);
        if (!flag){
            //key不存在，表示验证码已经失效，需要重行获取验证码
            //return ErrorResult.builder().errCode("000002").errMessage("验证码已失效~~请重新获取验证码！！").build();
            log.error("验证码已失效~~请重新获取验证码！！");
            result.put("message","验证码已失效~~请重新获取验证码！！");
            return result;
        }
        //验证码未失效，验证登录
        //获取Redis中的验证码
        String redisCode = redisTemplate.opsForValue().get(redisKey);
        code = code.toLowerCase();
        //校验验证码
        if (!(StrUtil.equals(code,redisCode))){
            //验证码验证失败,返回错误信息
            //return  ErrorResult.builder().errCode("000003").errMessage("验证码校验失败~~~请重新输入！！！").build();
            log.error("验证码校验失败~~~请重新输入！！！");
            result.put("message","验证码校验失败~~~请重新输入！！！");
            return result;
        }


        //判断该用户账号是否存在
        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<Admin>();
        //根据账号判断用户是否存在
        wrapper.eq(Admin::getUsername,username);
        Admin admin = adminMapper.selectOne(wrapper);
        //判断用户是否存在
        if (ObjectUtil.isEmpty(admin)){
            //用户信息为空，返回错误信息
            //return ErrorResult.builder().errCode("000004").errMessage("该账号不存在~~请重新登录！！").build();
            log.error("该账号不存在~~请重新登录！！");
            result.put("message","该账号不存在~~请重新登录！！");
            return result;
        }
        //用户存在，校验密码是否正确
        //获取管理员密码
        String adminPassword = admin.getPassword();
        //判断前端传入密码与管理员密码是否一致
        if (!StrUtil.equals(password,adminPassword)){
            //密码不一致，返回前端错误信息
            //return ErrorResult.builder().errCode("000005").errMessage("密码校验错误~~~请重行输入！！！").build();
            log.error("密码校验错误~~~请重行输入！！！");
            result.put("message","密码校验错误~~~请重行输入！！！");
            return result;
        }

        //验证码校验成功，删除Redis中的验证码
        redisTemplate.delete(redisKey);

        //将用户uid,用户名,头像存入body中
        Map<String , Object> claims = new HashMap<String, Object>();
        claims.put("uid",admin.getUid());
        claims.put("username",admin.getUsername());
        claims.put("avatar",admin.getAvatar());


        //生成token
        String token = Jwts.builder()
                .setClaims(claims) //payload，存放数据的位置，不能放置敏感数据，如：密码等
                .signWith(SignatureAlgorithm.HS256, secret) //设置加密方法和加密盐
                .setExpiration(new DateTime().plusHours(12).toDate()) //设置过期时间，12小时
                .compact();


        //设置返回token
        Map<String ,String> tokenMap = new HashMap<>();
        tokenMap.put("token",token);
        //密码正确,登录成功
        return tokenMap;
    }

    /*
     * 解析token
     * */
    public Admin queryAdminToken(String token){
        try {
            // 通过token解析数据
            Map<String, Object> body = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
            //获取payload中的用户uid,用户名,头像并封装
            Admin admin = new Admin();
            admin.setUid(Long.valueOf(body.get("uid").toString()));
            admin.setUsername(body.get("username").toString());
            admin.setAvatar(body.get("avatar").toString());
            //返回用户
            return admin;
        }catch (Exception e){
            return null;
        }
    }

    /**
     * 保存code到Redis
     * @param uuid
     * @param generateVerifyCode 验证码
     */
    public void saveCode(String uuid, String generateVerifyCode) {
        //创建验证码redisKey
        String redisKey = uuid;
        //保存验证码到Redis，失效时间为5分钟
        redisTemplate.opsForValue().set(redisKey,generateVerifyCode, Duration.ofMinutes(5));
    }

    /**
     * 用户登出
     * @return
     */
    public void logout(String token) {
        //黑名单思维，在登出时将token作为键存入Redis，设置失效时间为原token自动失效时间，方便释放Redis内存
        redisTemplate.opsForValue().set(token,"1",Duration.ofHours(12));
        //用户登出，将用户退出
        AdminThreadLocal.remove();
    }

    /**
     * 用户基本信息
     * @return 用户基本信息对象
     */
    public AdminVo profile() {
        //用户用户对象信息
        Admin admin = AdminThreadLocal.get();
        //创建返回实体类对象
        AdminVo adminVo = new AdminVo();
        adminVo.setUid(admin.getUid().toString());//用户id
        adminVo.setUsername(admin.getUsername());//用户名
        adminVo.setAvatar(admin.getAvatar());//用户头像

        //返回实体类对象
        return adminVo;
    }
}
